﻿using ModubsRTUTempactureCurve.Base;
using ModubsRTUTempactureCurve.Models;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Threading;



namespace ModubsRTUTempactureCurve.ViewModels
{
    public class MainViewModel : ObservableObject
    {

        private bool _isStart;
        private bool IsEnabled_Monitor = false;
        public bool IsStart
        {
            get { return _isStart; }
            set {
                _isStart = value;
                if (!value)
                {
                    this.ShowMessage("未打开监控,请打开监控开关",false);
                } else
                {
                    if (!IsEnabled_Monitor)//配置文件丢失,导致初始化失败
                    {
                        StartMonitor();
                        IsEnabled_Monitor = true;
                    }
                }
                RaisePropertyChanged(); }
        }

        private DateTime _currentDateTime;

        public DateTime CurrentDateTime
        {
            get { return _currentDateTime; }
            set { _currentDateTime = value; }
        }


        private bool _isLog;

        public bool IsLog
        {
            get { return _isLog; }
            set { _isLog = value; RaisePropertyChanged(); }
        }

        private int _blurRadius;

        public int BlurRadius
        {
            get { return _blurRadius; }
            set { _blurRadius = value; RaisePropertyChanged(); }
        }

        private bool _isFold = false; 

        public bool IsFold
        {
            get { return _isFold; }
            set { _isFold = value; RaisePropertyChanged(); }
        }

        private string _message;

        public string Message
        {
            get { return _message; }
            set
            {
                _message = value;
                RaisePropertyChanged();
            }
        }

        private string _msgColor = "#90EE90";

        public string MsgColor
        {
            get { return _msgColor; }
            set { _msgColor = value;
                RaisePropertyChanged();
            }
        }

        private string _portName;

        public string PortName
        {
            get { return _portName; }
            set
            {
                _portName = value;
                //if(serialPort!= null)//这里直接在配置时关闭串口，串口读取线程重新检查时就会重新配置打开
                //{
                //    if(serialPort.IsOpen)
                //    {
                //        serialPort.Close();
                //    }
                //    serialPort.PortName = _portName;
                //}
                RaisePropertyChanged();
            }
        }

        private int _baudRate;

        public int BaudRate
        {
            get { return _baudRate; }
            set { _baudRate = value;
                RaisePropertyChanged();
                
            }
        }

        private string _logPath;

        public string LogPath
        {
            get { return _logPath; }
            set { _logPath = value; RaisePropertyChanged(); }
        }
        public List<string> PortNameList { get; set; }
        public List<int> BuadRateList { get; set; }

        public DelegateCommand<string> ConfigCmd {get;set;} 
        public DelegateCommand CompletedCmd { get;set;}

        public DelegateCommand LogPathSelectCommand {get;set;}
        public DelegateCommand OpenLogPathCmd {get;set;}
       
        private volatile SerialPort serialPort;
        private List<Task> tasks = new List<Task>();
        private CancellationTokenSource cts = new CancellationTokenSource();
        // 定义异步锁（初始计数1，表示同时只允许1个线程访问）
        private readonly SemaphoreSlim _serialLock = new SemaphoreSlim(1, 1);
        private LogProvider logProvider;

        public ObservableCollection<ItemModel> ItemList {  get; set; }
        
        public MainViewModel() 
        {
            
            ConfigCmd = new DelegateCommand<string>(ExecuteConfig);
            LogPathSelectCommand = new DelegateCommand(LogPathSelect);
            OpenLogPathCmd = new DelegateCommand(OpenLogPath);
            //CompletedCmd = new DelegateCommand(CloseMask);
            ItemList = new ObservableCollection<ItemModel>();
            Random random = new Random();
            for (int i = 0; i < 4; i++)
            {
                double _value = random.Next(-20,100) * 1.0;
                ItemList.Add(new ItemModel() { SlaveId = i+1, Temperature = _value,Humidity=_value});
            }

            var task = new Task(async () => {
                while (!cts.IsCancellationRequested)
                {
                    CurrentDateTime = DateTime.Now;
                    await Task.Delay(1000);
                }
            },cts.Token);
            tasks.Add(task);
            PortNameList =  SerialPort.GetPortNames().ToList();
            BuadRateList = new List<int>() { 2400,4800,9600,14400,19200,38400,56000,115200};
            serialPort = new SerialPort();
            serialPort.WriteTimeout = 3000;
            serialPort.ReadTimeout = 5000;
            try
            {
                string json = File.ReadAllText("config.json");
                ConfigModel config = JsonConvert.DeserializeObject<ConfigModel>(json);
                this.PortName = config.PortName;
                this.BaudRate = config.BaudRate;
                this.LogPath = config.LogPath;
            }
            catch (Exception ex)
            {
                this.ShowMessage("初始化参数失败,需要重新设置串口参数" + ex.Message, false);
                return;
            }
            this.StartMonitor();
            logProvider = new LogProvider(this.LogPath);
            IsEnabled_Monitor = true;
        }

        

        private void OpenLogPath()
        {
            if (Directory.Exists(this.LogPath))
            {
                Process.Start("explorer.exe",this.LogPath);
            }
        }

        private void LogPathSelect()
        {
            FolderBrowserDialog folderDialog = new FolderBrowserDialog();
            var result = folderDialog.ShowDialog();
            if (result == DialogResult.OK)
            {
                this.LogPath = folderDialog.SelectedPath;
                logProvider.LogPath = this.LogPath;
            }
        }


        //private void CloseMask()
        //{
        //    IsFold = !IsFold;
        //}

        private void ExecuteConfig(string State)
        {
            IsStart = false;
            if (State.Equals("Open"))
            {
                
                BlurRadius = 10;
                serialPort.Close();
                IsFold = !IsFold;
            }
            else if(State.Equals("Close"))
            {
                BlurRadius = 0;
                try
                {
                    ConfigModel config = new ConfigModel();
                    config.PortName = this.PortName;
                    config.BaudRate = this.BaudRate;
                    config.LogPath = this.LogPath;

                    var json = JsonConvert.SerializeObject(config);
                    File.WriteAllText("config.json", json);

                    logProvider.WriteLog("配置文件修改完毕",IsLog);
                }
                catch (Exception ex) {
                    this.ShowMessage("写配置文件失败!" + ex.Message, false);
                    logProvider.WriteLog("写配置文件失败", IsLog,isError:true);
                    MessageBox.Show(ex.Message);
                }
                
            }
        }

        private void StartMonitor()
        {
            if(IsEnabled_Monitor) return;
            var task = Task.Factory.StartNew(async () => 
            {
                IsEnabled_Monitor = true;//只要初始化监控线程
                while (!cts.IsCancellationRequested)
                {
                    await Task.Delay(500);
                    Console.WriteLine("开启监控前无操作，监控线程还在");
                    if (!IsStart) { continue; }
                    Console.WriteLine("开启了监控，监控线程还在");
                    await DoSerialWorkAsync();

                }
                Console.WriteLine("监控线程退出");
                IsEnabled_Monitor = false;//只要初始化监控线程
            },cts.Token);
            tasks.Add(task);
        }

        private async Task DoSerialWorkAsync()
        {
            // 异步等待锁（替代lock）
            await _serialLock.WaitAsync();
            try 
            { 
                if (serialPort == null)
                {
                    serialPort = new SerialPort();
                }
                bool state = serialPort.IsOpen;
                if (!state)
                {
                    state = OpenSerial();
                }
                if (state)
                {

                    ShowMessage("串口已打开");
                    try
                    {
                        foreach (var item in this.ItemList)
                        {
                            await this.Read(item);
                        }
                    }
                    catch (Exception ex)
                    {
                        logProvider.WriteLog("读取寄存器失败,检查串口配置！" + ex.Message,IsLog, isError: true);
                        ShowMessage("读取寄存器失败,检查串口配置！" + ex.Message, false);
                    }

                }
            }
            finally
            {
                _serialLock.Release(); // 释放锁，避免死锁
            }
            

        }

        private bool OpenSerial()
        {
            try
            {
                if (serialPort == null)//配置文件没有，也没有配置
                {
                    serialPort = new SerialPort();
                }
                serialPort.PortName = this.PortName;
                serialPort.BaudRate = this.BaudRate;
                serialPort.Parity = Parity.None;
                serialPort.StopBits = StopBits.One;
                serialPort.WriteTimeout = 3000; 
                serialPort.ReadTimeout = 5000; 
                serialPort.Open();
                logProvider.WriteLog("串口打开成功",IsLog);
                return true;
            }
            catch (Exception ex)
            {
                logProvider.WriteLog("串口打开失败!检查串口配置" + ex.Message, IsLog,isError:true);
                ShowMessage("串口打开失败!检查串口配置" + ex.Message, false);
                return false;
            }
        }

        private async Task Read(ItemModel model)
        {
            try
            {   //读取地址+读取数量
                byte[] bytes = new byte[8];
                bytes[0] = (byte)model.SlaveId;
                bytes[1] = 0x03;
                bytes[2] = 0x00;
                bytes[3] = 0x00;
                bytes[4] = 0x00;
                bytes[5] = 0x02;
                CRC16(bytes);
                await serialPort.BaseStream.WriteAsync(bytes, 0, bytes.Length);
                await Task.Delay(300);
                if (serialPort.BytesToRead > 0)
                {
                    byte[] respBytes = new byte[serialPort.BytesToRead];
                    using (var readcts = new CancellationTokenSource(5000)) // 5秒超时
                    {
                        await serialPort.BaseStream.ReadAsync(respBytes, 0, respBytes.Length, readcts.Token);
                    }


                    byte[] checkArray = new byte[respBytes.Length];
                    Array.Copy(respBytes, checkArray, respBytes.Length);
                    this.CRC16(checkArray);
                    if (!Enumerable.SequenceEqual(respBytes, checkArray))
                    {
                        throw new Exception("接收报文校验错误");
                    }

                    if ((checkArray[1] & 0x80) == 0x80)
                    {
                        throw new Exception("接收报文校验错误");
                    }

                    var temp = BitConverter.ToInt16(new byte[] { checkArray[4], checkArray[3] }, 0);
                    var humi = BitConverter.ToInt16(new byte[] { checkArray[6], checkArray[5] }, 0);
                    model.Temperature = (double)(temp * 0.1);
                    model.Humidity = (double)(humi * 0.1);
                    logProvider.WriteLog($"从站[{model.SlaveId}]数据获取成功 温度/湿度:{temp*0.1}/{humi * 0.1}",this.IsLog);
                }
            }
            catch (Exception ex)
            {
                ShowMessage("读取寄存器失败,检查串口配置！" + ex.Message, false);
                throw ex;
            }
        }

        private void CRC16(byte[] value)
        {
            if (value == null || !value.Any())
                throw new ArgumentException("Value cannot be null or empty.");

            // 运算
            ushort crc = 0xFFFF;
            for (int i = 0; i < value.Length - 2; i++)
            {
                crc = (ushort)(crc ^ (value[i]));
                for (int j = 0; j < 8; j++)
                {
                    crc = (crc & 1) != 0 ? (ushort)((crc >> 1) ^ 0xA001) : (ushort)(crc >> 1);
                }
            }
            byte hi = (byte)((crc & 0xFF00) >> 8); // 高位置
            byte lo = (byte)(crc & 0x00FF);       // 低位置

            value[value.Length - 2] = lo;
            value[value.Length - 1] = hi;
        }

        private void ShowMessage(string message,bool state = true)
        {
            this.Message = message;
            this.MsgColor = state ? "#90EE90" : "#FF4500";
        }

        public void Dispose()
        {
            cts.Cancel();
            try
            {
                serialPort.Close();
                serialPort.Dispose();
                logProvider.WriteLog("对象已释放",IsLog);
                logProvider.Dispose();
                Task.WaitAll(tasks.ToArray(), 10000);
            }
            catch (AggregateException ex)
            {
                // 处理异常：筛选出非取消的异常（如果有）
                foreach (var innerEx in ex.InnerExceptions)
                {
                    if (innerEx is TaskCanceledException)
                    {
                        MessageBox.Show("任务因超时而被取消,不用在意");
                    }
                    else
                    {
                        MessageBox.Show($"任务出错：{innerEx.Message}");
                    }
                }
            }
            catch (Exception ex)
            {
                // 处理其他非AggregateException异常
                MessageBox.Show($"其他错误：{ex.Message}");
            }
            
        }
    }
}
